Skip to content

add support for QuerySet.annotate() #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 3, 2024

Conversation

timgraham
Copy link
Collaborator

No description provided.

@timgraham timgraham force-pushed the QuerySet.annotate branch from 85c4206 to e4cc20d Compare May 28, 2024 19:32
@timgraham timgraham marked this pull request as ready for review May 28, 2024 19:42
@timgraham timgraham requested a review from WaVEV May 28, 2024 19:42
@timgraham timgraham force-pushed the QuerySet.annotate branch from e4cc20d to 0dd8d6b Compare May 29, 2024 23:47
cursor.limit(int(self.query.high_mark - self.query.low_mark))
return cursor
pipeline.append({"$limit": self.query.high_mark - self.query.low_mark})
return self.collection.aggregate(pipeline)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I saw this in other PR. Is there any order to follow?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just rebased this on that PR (you can see it's the first commit here) to make sure everything works with that change. I'll merge that PR first, then rebase this again so this change disappears.

Copy link
Collaborator

@WaVEV WaVEV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, only a minor question about the converter indexing.

backend_converters = self.connection.ops.get_db_converters(column)
field_converters = column.field.get_db_converters(self.connection)
if backend_converters or field_converters:
converters[column.target.column] = backend_converters + field_converters
converters[name] = backend_converters + field_converters
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Django sql compiler uses an index. Like an integer and maintain the order.
https://github.com/mongodb-forks/django/blob/mongodb-5.0.x/django/db/models/sql/compiler.py#L1483

Copy link
Collaborator Author

@timgraham timgraham May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, however, MongoDB returns a document of (unordered?) fields, hence we may need to use the key lookup approach (or at least this was the reason for the original implementation in Django Mongo Engine + Python 2). Since Python 3.7 dictionaries are guaranteed to be insertion ordered. Not sure how the MongoDB server handles field ordering though (does it match the order of $project)? Could be checked but the idea is orthogonal to this PR which just builds on the existing implementation.

Copy link
Contributor

@Jibola Jibola left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. Great job switching this to use Aggregation!

Comment on lines 94 to 100
mongo_aggregates = {
"exact": lambda a, b: {"$eq": [a, b]},
"gt": lambda a, b: {"$gt": [a, b]},
"gte": lambda a, b: {"$gte": [a, b]},
"lt": lambda a, b: {"$lt": [a, b]},
"lte": lambda a, b: {"$lte": [a, b]},
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you need the iexact, startswith, endswith equivalents here as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's possible those lookups could be used as annotations, but I'm not sure the Django test suite covers it. I wouldn't worry about it unless we get a bug report.

@timgraham timgraham force-pushed the QuerySet.annotate branch 4 times, most recently from 51a65b5 to 06f34f8 Compare May 31, 2024 00:16
@timgraham
Copy link
Collaborator Author

While triaging the annotations tests, I found few more bugs which are fixed in the first two of the last three commits, so I'd appreciate it if you could review those.

@timgraham timgraham requested review from Jibola and WaVEV May 31, 2024 00:24
@@ -73,6 +91,13 @@ class DatabaseWrapper(BaseDatabaseWrapper):
"regex": lambda val: re.compile(val),
"iregex": lambda val: re.compile(val, re.IGNORECASE),
}
mongo_aggregates = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 In this PR add support for annotates, so Why is mongo_aggregates the name? shouldn't it be mongo_annotates? IMO aggregates sounds like $sum, $avg, and all this kind of group by operators.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally I called it mongo_functions but renamed it because https://www.mongodb.com/docs/manual/reference/operator/aggregation/lt/ describes it as "aggregation". Maybe it should be mongo_aggregations. I'm not sure the precise difference between aggregate and aggregation!

@@ -54,7 +54,25 @@ class DatabaseWrapper(BaseDatabaseWrapper):
"TimeField": "date",
"UUIDField": "string",
}
# Django uses these operators to generate SQL queries before it generates
# MQL queries.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on this? Why does SQL get generated if we're running a mongodb query?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to do with how this library hooks in to the query generation process. See also:

https://github.com/mongodb-labs/django-mongodb/blob/3c3ad0eb45a2572453aa228ddafac96391dc1ab8/django_mongodb/query.py#L23-L32

Copy link
Member

@blink1073 blink1073 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@timgraham timgraham force-pushed the QuerySet.annotate branch from 06f34f8 to db3b2d0 Compare June 3, 2024 19:10
@timgraham timgraham merged commit db3b2d0 into mongodb:main Jun 3, 2024
3 checks passed
@timgraham timgraham deleted the QuerySet.annotate branch June 3, 2024 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants